#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

using Newtonsoft.Utilities.Collections;
using NUnit.Framework;
using Newtonsoft.Utilities.Testing;

namespace Newtonsoft.Utilities.Tests.Collections
{
  public class KeyedListTests : TestsBase
  {
    protected KeyedList<string, int> k;

    public override void TestSetup()
    {
      k = new KeyedList<string, int>();
      k.Add("Zero", 0);
      k.Add("One", 1);
      k.Add("Two", 2);
      k.Add("Three", 3);
      k.Add("Four", 4);
      k.Add("Five", 5);
      k.Add("Six", 6);
      k.Add("Seven", 7);
      k.Add("Eight", 8);
      k.Add("Nine", 9);
      k.Add("Ten", 10);
    }

    [Test]
    public void ValueIteratorTest()
    {
      int idx = 0;

      foreach (int val in k.Values)
      {
        Assert.AreEqual(val, idx, "Itereator: Expected " + idx.ToString());
        ++idx;
      }
    }

    [Test]
    public void ValueByIndexTests()
    {
      Assert.AreEqual(k[0].Value, 0, "Indexer: Expected 0");
      Assert.AreEqual(k[1].Value, 1, "Indexer: Expected 1");
      Assert.AreEqual(k[2].Value, 2, "Indexer: Expected 2");
      Assert.AreEqual(k[3].Value, 3, "Indexer: Expected 3");
      Assert.AreEqual(k[4].Value, 4, "Indexer: Expected 4");
      Assert.AreEqual(k[5].Value, 5, "Indexer: Expected 5");
      Assert.AreEqual(k[6].Value, 6, "Indexer: Expected 6");
      Assert.AreEqual(k[7].Value, 7, "Indexer: Expected 7");
      Assert.AreEqual(k[8].Value, 8, "Indexer: Expected 8");
      Assert.AreEqual(k[9].Value, 9, "Indexer: Expected 9");
      Assert.AreEqual(k[10].Value, 10, "Indexer: Expected 10");
    }

    [Test]
    public void ValueByKeyTests()
    {
      Assert.AreEqual(k["Zero"], 0, "Lookup: Expected 0");
      Assert.AreEqual(k["One"], 1, "Lookup: Expected 1");
      Assert.AreEqual(k["Two"], 2, "Lookup: Expected 2");
      Assert.AreEqual(k["Three"], 3, "Lookup: Expected 3");
      Assert.AreEqual(k["Four"], 4, "Lookup: Expected 4");
      Assert.AreEqual(k["Five"], 5, "Lookup: Expected 5");
      Assert.AreEqual(k["Six"], 6, "Lookup: Expected 6");
      Assert.AreEqual(k["Seven"], 7, "Lookup: Expected 7");
      Assert.AreEqual(k["Eight"], 8, "Lookup: Expected 8");
      Assert.AreEqual(k["Nine"], 9, "Lookup: Expected 9");
      Assert.AreEqual(k["Ten"], 10, "Lookup: Expected 10");
    }

    [Test]
    public void IndexOfTests()
    {
      Assert.AreEqual(k.IndexOf("Zero"), 0, "IndexOf: Expected 0");
      Assert.AreEqual(k.IndexOf("One"), 1, "IndexOf: Expected 1");
      Assert.AreEqual(k.IndexOf("Two"), 2, "IndexOf: Expected 2");
      Assert.AreEqual(k.IndexOf("Three"), 3, "IndexOf: Expected 3");
      Assert.AreEqual(k.IndexOf("Four"), 4, "IndexOf: Expected 4");
      Assert.AreEqual(k.IndexOf("Five"), 5, "IndexOf: Expected 5");
      Assert.AreEqual(k.IndexOf("Six"), 6, "IndexOf: Expected 6");
      Assert.AreEqual(k.IndexOf("Seven"), 7, "IndexOf: Expected 7");
      Assert.AreEqual(k.IndexOf("Eight"), 8, "IndexOf: Expected 8");
      Assert.AreEqual(k.IndexOf("Nine"), 9, "IndexOf: Expected 9");
      Assert.AreEqual(k.IndexOf("Ten"), 10, "IndexOf: Expected 10");
    }

    [Test]
    public void ContainsKeyTests()
    {
      Assert.IsTrue(k.ContainsKey("Zero"), "Expected true");
      Assert.IsTrue(k.ContainsKey("One"), "Expected true");
      Assert.IsTrue(k.ContainsKey("Two"), "Expected true");
      Assert.IsTrue(k.ContainsKey("Three"), "Expected true");
      Assert.IsTrue(k.ContainsKey("Four"), "Expected true");
      Assert.IsTrue(k.ContainsKey("Five"), "Expected true");
      Assert.IsTrue(k.ContainsKey("Six"), "Expected true");
      Assert.IsTrue(k.ContainsKey("Seven"), "Expected true");
      Assert.IsTrue(k.ContainsKey("Eight"), "Expected true");
      Assert.IsTrue(k.ContainsKey("Nine"), "Expected true");
      Assert.IsTrue(k.ContainsKey("Ten"), "Expected true");
    }

    [Test]
    public void ContainsTests()
    {
      Assert.IsTrue(k.Contains(new KeyValuePair<string, int>("Zero", 0)), "Expected true");
      Assert.IsTrue(k.Contains(new KeyValuePair<string, int>("One", 1)), "Expected true");
      Assert.IsTrue(k.Contains(new KeyValuePair<string, int>("Two", 2)), "Expected true");
      Assert.IsTrue(k.Contains(new KeyValuePair<string, int>("Three", 3)), "Expected true");
      Assert.IsTrue(k.Contains(new KeyValuePair<string, int>("Four", 4)), "Expected true");
      Assert.IsTrue(k.Contains(new KeyValuePair<string, int>("Five", 5)), "Expected true");
      Assert.IsTrue(k.Contains(new KeyValuePair<string, int>("Six", 6)), "Expected true");
      Assert.IsTrue(k.Contains(new KeyValuePair<string, int>("Seven", 7)), "Expected true");
      Assert.IsTrue(k.Contains(new KeyValuePair<string, int>("Eight", 8)), "Expected true");
      Assert.IsTrue(k.Contains(new KeyValuePair<string, int>("Nine", 9)), "Expected true");
      Assert.IsTrue(k.Contains(new KeyValuePair<string, int>("Ten", 10)), "Expected true");
    }

    [Test]
    public void NotContainsKeyTest()
    {
      Assert.IsFalse(k.ContainsKey("Eleven"), "Expected false");
    }

    [Test]
    public void NotContainsTests()
    {
      Assert.IsFalse(k.Contains(new KeyValuePair<string, int>("Zero", 5)), "list does not contain kvp Zero-5");
      Assert.IsFalse(k.Contains(new KeyValuePair<string, int>("Eleven", 11)), "list does not contain kvp Eleven-11");
    }

    [Test]
    public void OrderedKeyTest()
    {
      int idx = 0;

      foreach (string key in k.OrderedKeys)
      {
        Assert.AreEqual(key, k.GetKey(idx++), "Expected key to match indexed key.");
      }
    }

    [Test]
    public void OrderedValueTest()
    {
      int idx = 0;

      foreach (int val in k.OrderedValues)
      {
        Assert.AreEqual(val, k[idx++].Value, "Expected value to match indexed value.");
      }
    }

    [Test]
    [ExpectedException(typeof(ArgumentOutOfRangeException))]
    public void NegativeIndexTest()
    {
      int foo = k[-1].Value;
    }

    [Test]
    [ExpectedException(typeof(ArgumentOutOfRangeException))]
    public void IndexToLargeTest()
    {
      int foo = k[k.Count].Value;
    }

    [Test]
    [ExpectedException(typeof(KeyNotFoundException))]
    public void BadKeyTest()
    {
      int foo = k["Eleven"];
    }

    [Test]
    public void IndexOfNotFound()
    {
      Assert.AreEqual(k.IndexOf("Foo"), -1, "Expected the returned index to be -1.");
    }
  }

  public class SequencedKeyedListTests : TestsBase
  {
    protected KeyedList<string, double> k;

    public override void  TestSetup()
    {
      k = new KeyedList<string, double>();
      k.Add("Zero", 0);
      k.Add("One", 1);
      k.Add("Two", 2);
      k.Add("Three", 3);
      k.Add("Four", 4);
      k.Add("Five", 5);
      k.Add("Six", 6);
      k.Add("Seven", 7);
      k.Add("Eight", 8);
      k.Add("Nine", 9);
      k.Add("Ten", 10);
    }


    [Test]
    public void CopyToTest()
    {
      KeyValuePair<string, double>[] kvpa = new KeyValuePair<string, double>[k.Count];
      k.CopyTo(kvpa, 0);
      int idx = 0;

      foreach (KeyValuePair<string, double> kvp in kvpa)
      {
        Assert.AreEqual(kvp.Key, k.GetKey(idx), "KeyValuePair not ordered.");
        Assert.AreEqual(kvp.Value, k[idx].Value, "KeyValuePair not ordered.");
        ++idx;
      }
    }

    [Test]
    [ExpectedException(typeof(ArgumentException))]
    public void CopyToArraySizeExceptionTest()
    {
      KeyValuePair<string, double>[] kvpa = new KeyValuePair<string, double>[k.Count];
      k.CopyTo(kvpa, 5);
    }

    [Test]
    public void AddTest()
    {
      k.Add("Eleven", 11);
      Assert.AreEqual(k[k.Count - 1].Value, 11, "Expected the last entry to be 11.");
    }

    [Test]
    public void AddTestByKeyValuePair()
    {
      k.Add(new KeyValuePair<string, double>("Twelve", 12));
      Assert.AreEqual(k[k.Count - 1].Value, 12, "Expected the last entry to be 12.");
    }

    [Test]
    public void InsertTest()
    {
      k.Insert(2, "One Point Five", 1.5);
      Assert.AreEqual(k[1].Value, 1, "Expected [1] entry to = 1");
      Assert.AreEqual(k[2].Value, 1.5, "Expected [2] entry to = 1.5");
      Assert.AreEqual(k[3].Value, 2, "Expected [3] entry to = 2");
    }

    [Test]
    public void RemoveTest()
    {
      bool ret = k.Remove("One");
      Assert.IsTrue(ret, "Expected true");
      Assert.AreEqual(k[1].Value, 2, "Expected [1] entry to = 2");
      Assert.AreEqual(k[2].Value, 3, "Expected [2] entry to = 3");
    }

    [Test]
    public void RemoveNotFoundTest()
    {
      bool ret = k.Remove("One Point Five");
      Assert.IsFalse(ret, "Expected false");
    }

    [Test]
    public void RemoveByKeyValuePair()
    {
      KeyValuePair<string, double> kvp = new KeyValuePair<string, double>("Nine", 9);
      bool ret = k.Remove(kvp);
      Assert.IsTrue(ret, "Expected true");
      Assert.AreEqual(k[9].Value, 10, "Expected entry 10 to be removed");
    }

    [Test]
    public void RemoveNotFoundByKeyValuePair()
    {
      // value is ignored.
      KeyValuePair<string, double> kvp = new KeyValuePair<string, double>("Eleven", 0);
      bool ret = k.Remove(kvp);
      Assert.IsFalse(ret, "Expected false");
    }

    [Test]
    public void RemoveAtTest()
    {
      k.RemoveAt(1);
      Assert.AreEqual(k[0].Value, 0, "Expected [0] entry to = 0");
      Assert.AreEqual(k[1].Value, 2, "Expected [1] entry to = 2");
    }

    [Test]
    public void TryGetValueTest()
    {
      double v;
      bool ret = k.TryGetValue("Ten", out v);
      Assert.IsTrue(ret, "Expected true");
      Assert.AreEqual(v, 10, "Expected return value = 10");
    }

    [Test]
    public void TryGetValueNotFoundTest()
    {
      double v;
      bool ret = k.TryGetValue("Elevent", out v);
      Assert.IsFalse(ret, "Expected false");
      Assert.AreEqual(v, 0, "Expected return value = default value");
    }

    [Test]
    public void EmptyListInsertAtZero()
    {
      k.Clear();
      k.Insert(0, "Z", 0);
      Assert.AreEqual(k[0].Value, 0, "Expected a value of 0");
    }
  }

  public class EnumeratorTests : TestsBase
  {
    protected KeyedList<string, int> k;

    public override void TestSetup()
    {
      k = new KeyedList<string, int>();
      k.Add("Zero", 0);
      k.Add("One", 1);
      k.Add("Two", 2);
      k.Add("Three", 3);
      k.Add("Four", 4);
      k.Add("Five", 5);
      k.Add("Six", 6);
      k.Add("Seven", 7);
      k.Add("Eight", 8);
      k.Add("Nine", 9);
      k.Add("Ten", 10);
    }

    [Test]
    public void DefaultEnumerator()
    {
      //foreach(object obj in k)
      //{
      //}
    }

    [Test]
    public void EnumerationTest()
    {
      int n = 0;

      foreach (KeyValuePair<string, int> kvp in k)
      {
        Assert.AreEqual(kvp.Value, n, "Expected ordered list of values.");
        ++n;
      }
    }

    [Test]
    public void ValueEnumeratorTest()
    {
      int n = 0;

      foreach (int i in k.OrderedValues)
      {
        Assert.AreEqual(n, i, "Expected ordered list of values.");
        ++n;
      }
    }

    [Test]
    public void KeyEnumeratorTest()
    {
      int n = 0;

      foreach (string s in k.OrderedKeys)
      {
        Assert.AreEqual(k.GetKey(n), s, "Expected ordered list of keys.");
        ++n;
      }
    }
  }
}